#pragma once

#include <iostream>
#include <string>
#include <cstdarg>
#include <ctime>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <cstdlib>

#define SIZE 1024 // 缓冲区大小

// 日志等级宏定义
#define INFO 0
#define DEBUG 1
#define WARNING 2
#define ERROR 3
#define FATAL 4

// 输出方式宏定义
#define Screen 1
#define Onefile 2
#define Classfile 3
#define ScreenAndFile 4 // 新增：同时向屏幕和文件输出

// 默认日志文件名
#define LogFile "log.txt"

class Log
{
public:
    Log() : printMethod(Screen), path("./log/")
    {
        // 检查日志目录是否存在，如果不存在则创建
        struct stat st = {0};
        if (stat(path.c_str(), &st) == -1)
        {
            mkdir(path.c_str(), 0700); // 创建目录，权限设置为 0700
        }
    }

    // 设置输出方式
    void Enable(int method)
    {
        printMethod = method;
    }

    // 将日志等级转换为字符串表示
    std::string levelToString(int level)
    {
        switch (level)
        {
        case INFO:
            return "Info";
        case DEBUG:
            return "Debug";
        case WARNING:
            return "Warning";
        case ERROR:
            return "Error";
        case FATAL:
            return "Fatal";
        default:
            return "None";
        }
    }

    // 输出日志到指定目的地
    void printLog(int level, const std::string &logtxt)
    {
        switch (printMethod)
        {
        case Screen:
            std::cout << logtxt << std::endl;
            break;
        case Onefile:
            printOneFile(LogFile, logtxt);
            break;
        case Classfile:
            printClassfile(level, logtxt);
            break;
        case ScreenAndFile: // 同时向屏幕和文件输出
            std::cout << logtxt << std::endl;
            printOneFile(LogFile, logtxt);
            break;
        default:
            break;
        }
    }

    // 输出到单一日志文件
    void printOneFile(const std::string &logname, const std::string &logtxt)
    {
        std::string fullLogPath = path + logname; // 构建完整路径
        int fd = open(fullLogPath.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0666);
        if (fd < 0)
            return;
        write(fd, logtxt.c_str(), logtxt.size());
        close(fd);
    }

    // 按照日志等级输出到不同文件
    void printClassfile(int level, const std::string &logtxt)
    {
        std::string filename = LogFile;
        filename += ".";
        filename += levelToString(level); // log.txt.Debug/Warning/Fatal...
        printOneFile(filename, logtxt);
    }

    // 重载 () 操作符，处理日志格式化和输出
    void operator()(int level, const char *format, ...)
    {
        // 获取当前时间
        time_t t = time(nullptr);
        struct tm *ctime = localtime(&t);

        // 构建默认的日志头（时间和日志等级）
        std::string defaultLogHeader = "[" + levelToString(level) + "][" +
                                       std::to_string(ctime->tm_year + 1900) + "-" +
                                       std::to_string(ctime->tm_mon + 1) + "-" +
                                       std::to_string(ctime->tm_mday) + " " +
                                       std::to_string(ctime->tm_hour) + ":" +
                                       std::to_string(ctime->tm_min) + ":" +
                                       std::to_string(ctime->tm_sec) + "]";

        // 处理可变参数部分
        va_list args;
        va_start(args, format);
        char buffer[SIZE * 2];
        vsnprintf(buffer, sizeof(buffer), format, args); // 格式化可变参数字符串
        va_end(args);

        // 拼接最终日志字符串
        std::string logtxt = defaultLogHeader + " " + std::string(buffer) + "\n";

        // 输出日志
        printLog(level, logtxt);
    }

private:
    int printMethod;  // 日志输出方式
    std::string path; // 日志文件路径
};
